package com.rabbit.eap.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rabbit.eap.framework.common.api.ApiResult;
import com.rabbit.eap.framework.common.enums.MsgEnum;
import com.rabbit.eap.framework.common.service.impl.BaseServiceImpl;
import com.rabbit.eap.framework.core.pagination.PageInfo;
import com.rabbit.eap.framework.core.pagination.Paging;
import com.rabbit.eap.system.dto.SysRoleDTO;
import com.rabbit.eap.system.entity.*;
import com.rabbit.eap.system.enums.RoleStateEnum;
import com.rabbit.eap.system.mapper.SysRoleMapper;
import com.rabbit.eap.system.mapper.SysUserRoleMapper;
import com.rabbit.eap.system.param.SysRolePageParam;
import com.rabbit.eap.system.service.ISysRoleDeptService;
import com.rabbit.eap.system.service.ISysRoleMenuService;
import com.rabbit.eap.system.service.ISysRoleService;
import com.rabbit.eap.system.vo.SysRoleVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @projectName: eap
 * @packageName: com.rabbit.eap.system.service.impl
 * @className SysRoleServiceImpl
 * @author： rabbit
 * @version： 1.0
 * @since： 2020/06/06 23:34:03
 * <p>Description:
 * 角色信息表 服务实现类
 * </p>

 */
@Slf4j
@Service
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private ISysRoleDeptService iSysRoleDeptService;

    @Autowired
    private ISysRoleMenuService iSysRoleMenuService;

    /**
     * @param sysRoleDTO:sysRoleDTO数据传输对象
     * @throws Exception
     * @Description: 添加角色信息表
     * @methodName: saveSysRole
     * @return: ApiResult
     * @date: 2020/06/06 23:34:03
     * @author: rabbit
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResult saveSysRole(SysRoleDTO sysRoleDTO) throws Exception {
        checkRole(sysRoleDTO);

        SysRole sysRole = sysRoleDTO.convert(SysRole.class);
        boolean bool = super.save(sysRole);
        boolean flag = saveSysRoleMenu(sysRole);
        if (bool && flag) {
            return ApiResult.ok(MsgEnum.ADD_SUCCESS.getDesc());
        } else {
            return ApiResult.fail(MsgEnum.ADD_FAIL.getDesc());
        }
    }

    /**
     * @param sysRoleDTO:sysRoleDTO数据传输对象
     * @throws Exception
     * @Description 修改角色信息表
     * @methodName: modifySysRole
     * @return: ApiResult
     * @date: 2020/06/06 23:34:03
     * @author: rabbit
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResult modifySysRole(SysRoleDTO sysRoleDTO) throws Exception {
        checkRole(sysRoleDTO);
        SysRole sysRole = sysRoleDTO.convert(SysRole.class);
        boolean bool = super.updateById(sysRole);
        iSysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, sysRole.getId()));
        boolean flag = saveSysRoleMenu(sysRole);
        if (bool && flag) {
            return ApiResult.ok(MsgEnum.UPDATE_SUCCESS.getDesc());
        } else {
            return ApiResult.fail(MsgEnum.UPDATE_FAIL.getDesc());
        }
    }

    private boolean saveSysRoleMenu(SysRole sysRole) {
        boolean flag = false;
        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
        for (Long menuId : sysRole.getMenuIds()) {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(sysRole.getId());
            sysRoleMenu.setMenuId(menuId);
            list.add(sysRoleMenu);
        }
        if (list.size() > 0) {
            flag = iSysRoleMenuService.saveBatch(list);
        }
        return flag;
    }

    /**
     * @param roleId:角色id
     * @throws Exception
     * @Description 删除角色信息表
     * @methodName: removeSysRole
     * @return: ApiResult
     * @date: 2020/06/06 23:34:03
     * @author: rabbit
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResult removeSysRole(Long roleId) throws Exception {
        if (ObjectUtil.isNull(roleId)) {
            return ApiResult.fail(RoleStateEnum.ROLE_ID.getDesc() + MsgEnum.NOT_NULL.getDesc());
        }
        SysRole sysRole = baseMapper.selectById(roleId);
        int count = sysUserRoleMapper.selectCount(
                new QueryWrapper<SysUserRole>().lambda().eq(SysUserRole::getRoleId, roleId)
        );
        if (count > 0) {
            return ApiResult.fail(String.format(RoleStateEnum.CNA_NOT_DELETE.getDesc(), sysRole.getRoleName()));
        }
        boolean bool = super.removeById(roleId);
        if (bool) {
            return ApiResult.ok(MsgEnum.DELETE_SUCCESS.getDesc());
        } else {
            return ApiResult.fail(MsgEnum.DELETE_FAIL.getDesc());
        }
    }

    /**
     * @param id: id
     * @throws Exception
     * @Description 根据Id获取角色信息表详情
     * @methodName: getSysRoleInfo
     * @return: ApiResult
     * @date: 2020/06/06 23:34:03
     * @author: rabbit
     */
    @Override
    public ApiResult getSysRoleById(Long id) throws Exception {
        if (ObjectUtil.isNull(id)) {
            return ApiResult.fail(RoleStateEnum.ROLE_ID.getDesc() + MsgEnum.NOT_NULL.getDesc());
        }
        SysRole sysRole = super.getById(id);
        SysRoleVO sysRoleVO = sysRole.convert(SysRoleVO.class);
        return ApiResult.ok(sysRoleVO);
    }

    /**
     * @param sysRolePageParam
     * @throws Exception
     * @Description 角色信息表分页列表
     * @methodName: getSysRolePageList
     * @return: ApiResult
     * @date: 2020/06/06 23:34:03
     * @author: rabbit
     */
    @Override
    public ApiResult getSysRolePageList(SysRolePageParam sysRolePageParam) throws Exception {
        Page<SysRole> page = new PageInfo<>(sysRolePageParam, OrderItem.desc("create_time"));
        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(StringUtils.isNotBlank(sysRolePageParam.getStatus()), SysRole::getStatus, sysRolePageParam.getStatus())
                .like(StringUtils.isNotBlank(sysRolePageParam.getRoleName()), SysRole::getRoleName, sysRolePageParam.getRoleName());
        IPage<SysRoleVO> iPage = sysRoleMapper.selectPage(page, queryWrapper).convert(sysRole -> sysRole.convert(SysRoleVO.class));
        Paging<SysRoleVO> paging = new Paging<SysRoleVO>(iPage);
        return ApiResult.ok(paging);
    }

    /**
     * @param userId: 用户Id
     * @Description: 根据用户ID查询角色
     * @methodName: selectRolePermissionByUserId
     * @return: java.util.Set<java.lang.String>
     * @date: 2020/6/29 21:29
     * @author: rabbit
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<SysRole> perms = sysRoleMapper.selectRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (SysRole perm : perms) {
            if (ObjectUtils.isNotEmpty(perm)) {
                permsSet.addAll(Arrays.asList(perm.getId().toString().trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * @param userId: 用户Id
     * @Description: 根据用户ID查询权限
     * @methodName: selectMenuPermsByUserId
     * @return: java.util.Set<java.lang.String>
     * @date: 2020/6/29 21:30
     * @author: rabbit
     */
    @Override
    public Set<String> selectMenuPermsByUserId(Long userId) {
        return null;
    }

    /**
     * @param userId: 用户Id
     * @Description: 根据用户获取角色
     * @methodName: getRoles
     * @return: java.util.List<com.rabbit.eap.system.entity.SysRole>
     * @date: 2020/6/29 21:30
     * @author: rabbit
     */
    @Override
    public List<SysRole> getRoles(Long userId) {
        List<SysRole> perms = sysRoleMapper.selectRolePermissionByUserId(userId);
        return perms;
    }

    /**
     * @param sysRoleDTO:
     * @Description: 校验角色名称是否唯一
     * @methodName: checkRoleNameUnique
     * @return: boolean true为否 false为是
     * @date: 2020/6/29 21:34
     * @author: rabbit
     */
    private boolean checkRoleNameUnique(SysRoleDTO sysRoleDTO) {
        Long roleId = ObjectUtil.isNull(sysRoleDTO.getId()) ? -1L : sysRoleDTO.getId();
        SysRole sysRole = sysRoleMapper.selectOne(
                new QueryWrapper<SysRole>().lambda().eq(SysRole::getRoleName, sysRoleDTO.getRoleName())
        );
        boolean flag = ObjectUtil.isNotNull(sysRole) && sysRole.getId().longValue() != roleId.longValue();
        if (flag) {
            return true;
        }
        return false;
    }

    /**
     * @param sysRoleDTO: true为否 false为是
     * @Description: 校验角色key是否唯一
     * @methodName: checkRoleKeyUnique
     * @return: boolean
     * @date: 2020/7/9 21:51
     * @author: rabbit
     */
    private boolean checkRoleKeyUnique(SysRoleDTO sysRoleDTO) {
        Long roleId = ObjectUtil.isNull(sysRoleDTO.getId()) ? -1L : sysRoleDTO.getId();
        SysRole sysRole = sysRoleMapper.selectOne(
                new QueryWrapper<SysRole>().lambda().eq(SysRole::getRoleKey, sysRoleDTO.getRoleKey())
        );
        boolean flag = ObjectUtil.isNotNull(sysRole) && sysRole.getId().longValue() != roleId.longValue();
        if (flag) {
            return true;
        }
        return false;
    }

    /**
     * @param sysRoleDTO:
     * @Description: 校验角名称及key是否唯一
     * @methodName: checkRole
     * @return: com.rabbit.eap.framework.common.api.ApiResult<java.lang.String>
     * @date: 2020/7/9 21:54
     * @author: rabbit
     */
    private ApiResult<String> checkRole(SysRoleDTO sysRoleDTO) {
        if (checkRoleNameUnique(sysRoleDTO)) {
            return ApiResult.fail(RoleStateEnum.ROLE_HAS_EXIST.getDesc());
        }
        if (checkRoleKeyUnique(sysRoleDTO)) {
            return ApiResult.fail(RoleStateEnum.ROLE_PRIVILEGE_EXIST.getDesc());
        }
        return null;
    }

    /**
     * @param sysRoleDTO:
     * @Description: 修改角色状态
     * @methodName: modifySysRoleStatus
     * @return: com.rabbit.eap.framework.common.api.ApiResult
     * @date: 2020/7/9 22:17
     * @author: rabbit
     */
    @Override
    public ApiResult modifySysRoleStatus(SysRoleDTO sysRoleDTO) {
        if (ObjectUtil.isNull(sysRoleDTO.getId())) {
            return ApiResult.fail(RoleStateEnum.ROLE_ID.getDesc() + MsgEnum.NOT_NULL.getDesc());
        }
        SysRole sysRole = new SysRole();
        sysRole.setId(sysRoleDTO.getId());
        sysRole.setStatus(sysRoleDTO.getStatus());
        boolean bool = super.updateById(sysRole);
        if (bool) {
            return ApiResult.ok(MsgEnum.UPDATE_SUCCESS.getDesc());
        } else {
            return ApiResult.fail(MsgEnum.UPDATE_FAIL.getDesc());
        }
    }

    /**
     * @param :
     * @Description: 获取角色选择框列表
     * @methodName: getSysRoleSelect
     * @return: com.rabbit.eap.framework.common.api.ApiResult
     * @date: 2020/7/9 22:30
     * @author: rabbit
     */
    @Override
    public ApiResult getSysRoleSelect() {
        List<SysRole> list = sysRoleMapper.getSysRoleSelect();
        return ApiResult.ok(list);
    }

    /**
     * @param sysRole:
     * @Description: 数据权限
     * @methodName: dataScope
     * @return: com.rabbit.eap.framework.common.api.ApiResult
     * @date: 2020/7/9 22:50
     * @author: rabbit
     */
    @Override
    public ApiResult authDataScope(SysRole sysRole) {
        boolean flag = false;
        // 删除角色与部门关联
        iSysRoleDeptService.remove(
                new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, sysRole.getId())
        );
        boolean bool = super.updateById(sysRole);
        //新增角色和部门数据权限
        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
        for (Long deptId : sysRole.getDeptIds()) {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(sysRole.getId());
            rd.setDeptId(deptId);
            list.add(rd);
        }
        if (ObjectUtil.isNotNull(list)) {
            flag = iSysRoleDeptService.saveBatch(list);
        }
        if (bool && flag) {
            return ApiResult.ok(RoleStateEnum.AUTH_DATA_SCOPE_SUCCESS.getDesc());
        } else {
            return ApiResult.fail(RoleStateEnum.AUTH_DATA_SCOPE_FAIL.getDesc());
        }
    }

    /**
     * @param sysRole:
     * @Description: 分配菜单权限
     * @methodName: authRoleMenu
     * @return: com.rabbit.eap.framework.common.api.ApiResult
     * @date: 2020/7/9 23:08
     * @author: rabbit
     */
    @Override
    public ApiResult authRoleMenu(SysRole sysRole) {
        boolean flag = false;
        // 删除角色与菜单关联
        boolean bool = iSysRoleMenuService.remove(
                new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, sysRole.getId())
        );
        //新增角色和菜单权限
        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
        for (Long menuId : sysRole.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(sysRole.getId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (ObjectUtil.isNotNull(list)) {
            flag = iSysRoleMenuService.saveBatch(list);
        }
        if (bool && flag) {
            return ApiResult.ok(RoleStateEnum.AUTH_ROLE_MENU_SUCCESS.getDesc());
        } else {
            return ApiResult.fail(RoleStateEnum.AUTH_ROLE_MENU_FAIL.getDesc());
        }
    }

    /**
     * @param :
     * @Description: 获取所有角色
     * @methodName: getRoleList
     * @return: com.rabbit.eap.framework.common.api.ApiResult
     * @date: 2020/9/25 20:00
     * @author: rabbit
     */
    @Override
    public ApiResult getRoleList() {
        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysRole::getStatus, StringPool.ZERO);
        List<SysRole> list = sysRoleMapper.selectList(queryWrapper);
        return ApiResult.ok(list);
    }
}
